home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / tcp_ip / jnos / jnos_src / main.c < prev    next >
C/C++ Source or Header  |  1994-08-26  |  59KB  |  2,195 lines

  1. /* Main-level network program:
  2.  * initialization
  3.  * keyboard processing
  4.  * generic user commands
  5.  *
  6.  * Copyright 1991 Phil Karn, KA9Q
  7.  */
  8. #include <time.h>
  9. #if defined(__TURBOC__) && defined(MSDOS)
  10. #include <fcntl.h>
  11. #include <dos.h>
  12. #include <io.h>
  13. #include <conio.h>
  14. #include <ctype.h>
  15. #include <dir.h>
  16. #include <alloc.h>
  17. #endif
  18. #ifdef LINUX
  19. #include <fcntl.h>
  20. #endif
  21. #include "global.h"
  22. #ifdef  ANSIPROTO
  23. #include <stdarg.h>
  24. #endif
  25. #include "mbuf.h"
  26. #include "timer.h"
  27. #include "proc.h"
  28. #include "iface.h"
  29. #include "ip.h"
  30. #include "tcp.h"
  31. #include "udp.h"
  32. #include "ax25.h"
  33. #include "kiss.h"
  34. #include "enet.h"
  35. #include "netrom.h"
  36. #include "ftpcli.h"
  37. #include "telnet.h"
  38. #include "tty.h"
  39. #include "session.h"
  40. #include "hardware.h"
  41. #include "bm.h"
  42. #include "usock.h"
  43. #include "socket.h"
  44. #ifdef LZW
  45. #include "lzw.h"
  46. #endif
  47. #include "cmdparse.h"
  48. #include "commands.h"
  49. #include "daemon.h"
  50. #include "devparam.h"
  51. #include "domain.h"
  52. #include "files.h"
  53. #include "main.h"
  54. #include "mailbox.h"
  55. #include "remote.h"
  56. #include "trace.h"
  57. #include "mailutil.h"
  58. #include "smtp.h"
  59. #include "index.h"
  60. #include "version.h"
  61. #ifdef XMS
  62. #include "xms.h"
  63. #endif
  64. #ifdef EMS
  65. #include "memlib.h"
  66. #endif
  67.   
  68. #undef BETA 1
  69.   
  70. #ifdef LINUX
  71. #define BETA 1
  72. #endif
  73. #ifdef BSAHAX
  74. #define BETA 1
  75. #endif
  76.   
  77. #if defined(__TURBOC__) || (defined __BORLANDC__)
  78. /* Don't even think about changing the following #pragma :-) - WG7J */
  79. #pragma option -a-
  80.   
  81. /* The following is from the Borland Runtime Library Version 3.0 :
  82.  * Copyright (c) 1987, 1990 by Borland International
  83.  */
  84. typedef struct
  85. {
  86.     unsigned char windowx1;
  87.     unsigned char windowy1;
  88.     unsigned char windowx2;
  89.     unsigned char windowy2;
  90.     unsigned char attribute;
  91.     unsigned char normattr;
  92.     unsigned char currmode;
  93.     unsigned char screenheight;
  94.     unsigned char screenwidth;
  95.     unsigned char graphicsmode;
  96.     unsigned char snow;
  97.     union {
  98.         char far * p;
  99.         struct { unsigned off,seg; } u;
  100.     } displayptr;
  101. } VIDEOREC;
  102. extern VIDEOREC _video;
  103.   
  104. char *Screen_Address(void){
  105.     /* Might have to add some code to get the address of the virtualized
  106.      * DV screen here, if we go that route.
  107.      */
  108.     return _video.displayptr.p;
  109. }
  110. #pragma option -a
  111.   
  112. #endif /* TURBOC || BORLANDC */
  113.   
  114. extern struct cmds DFAR Cmds[],DFAR Startcmds[],DFAR Stopcmds[],DFAR Attab[];
  115.   
  116. #if     (!defined(MSDOS) || defined(ESCAPE))    /* PC uses F-10 key always */
  117. static char Escape = 0x1d;      /* default escape character is ^] */
  118. #endif
  119.   
  120. #ifdef __TURBOC__
  121. int dofstat __ARGS((void));
  122. #endif
  123. static char Prompt[] = "jnos> ";
  124. char NoRead[] = "Can't read %s: %s\n";
  125. char Badhost[] = "Unknown host %s\n";
  126. char Badinterface[] = "Interface \"%s\" unknown\n";
  127. char Existingiface[] = "Interface %s already exists\n";
  128. char Nospace[] = "No space!!\n";    /* Generic malloc fail message */
  129. char Nosversion[] = "JNOS version %s\n";
  130. char NosLoadInfo[] = "NOS load info: CS=0x%04x DS=0x%04x";
  131. char Noperm[] = "Permission denied.\n";
  132. char Nosock[] = "Can't create socket\n";
  133. char SysopBusy[] = "The sysop is busy. Try again later.\n";
  134. char TelnetMorePrompt[] = "--more--";
  135. char BbsMorePrompt[] = "More(N=no)? ";
  136. char *Hostname;
  137. char *Motd;                     /* Message Of The Day */
  138. #if !defined MAILBOX || defined TTYLINKSERVER || defined TTYCALL
  139. int Attended = TRUE;            /* default to attended mode */
  140. #else
  141. int Attended;
  142. #endif
  143. int ThirdParty = TRUE;                  /* Allows 3rd party mail by default */
  144. int main_exit;          /* from main program (flag) */
  145. int DosPrompt;          /* Use a dos-like prompt */
  146. int Mprunning;          /* flag for other parts (domain) to signal
  147.              * that we are fully configured running.
  148.              */
  149. static int ErrorPause;
  150. static int Step;
  151. static int RmLocks = 1;
  152.   
  153. extern int StLen2;
  154. extern char *StBuf2;
  155. extern char *StBuf3;
  156. #ifdef MAILBOX
  157. #define MAXSTATUSLINES 3
  158. #else
  159. #define MAXSTATUSLINES 2
  160. #endif
  161. #ifdef STATUSWIN
  162. int StatusLines = MAXSTATUSLINES;
  163. #else
  164. int StatusLines = 0;
  165. #endif
  166.   
  167. struct proc *Cmdpp;
  168. #ifndef LINUX
  169. struct proc *Display;
  170. #endif
  171. #ifdef  LZW
  172. int Lzwmode = LZWCOMPACT;
  173. int16 Lzwbits = LZWBITS;
  174. #endif
  175.   
  176. #ifdef TRACE
  177. int Tracesession = 1;
  178. struct session *Trace = NULLSESSION;
  179. #endif
  180.   
  181. static char *DumpAddr = NULL;           /* Memory dump pointer */
  182. static FILE *Logfp;
  183. time_t StartTime;        /* Time that NOS was started */
  184. static int Verbose;
  185.   
  186. static void ctohex __ARGS((char *buf,int16 c));
  187. static void fmtline __ARGS((int16 addr,char *buf,int16 len));
  188. extern void assign_filenames __ARGS((char *));
  189. static void logcmd __ARGS((char *));
  190. char *Screen_Address(void);
  191.   
  192.   
  193. int Numrows,Numcols;    /* screen size at startup - WG7J */
  194. struct hist *Histry;    /* command recall stuff */
  195. int Histrysize;
  196. int Maxhistory = 10;
  197.   
  198. #ifdef EMS
  199. int EMS_Available;
  200. #endif
  201. #ifdef XMS
  202. int XMS_Available;
  203. #endif
  204.   
  205. #ifdef LINUX
  206. static char **origargv;
  207. #endif
  208.   
  209. /* The text_info before we start JNOS */
  210. struct text_info PrevTi;
  211. #ifdef STATUSWIN
  212. extern char MainStColors,SesStColors;
  213. #endif
  214. #ifdef SPLITSCREEN
  215. extern char MainColors,SplitColors;
  216. void GiveColor(char *s,char *attr);
  217. #endif
  218.   
  219. int
  220. main(argc,argv)
  221. int argc;
  222. char *argv[];
  223. {
  224.     int ForceIndex = 0;
  225.     char *inbuf,*intmp;
  226.     FILE *fp;
  227.     struct mbuf *bp;
  228.     int c,i;
  229. #ifdef LINUX
  230.     static int oops;
  231. #endif
  232.     struct cur_dirs dirs;
  233. #ifdef EMS
  234.     unsigned long emssize;
  235. #endif
  236. #ifdef XMS
  237.     long XMS_Ret;
  238. #endif
  239.   
  240. #ifdef LINUX
  241.     if (oops++)
  242.     {
  243.         iostop();
  244.         fprintf(stderr, "NOS PANIC: NOS main re-entered.\n");
  245.         fflush(stderr);
  246.         fflush(stdout);
  247.         kill(getpid(), 11);
  248.     }
  249.     origargv = argv;
  250. #endif
  251.   
  252.     StartTime = time(&StartTime);           /* NOS Start_Up time */
  253. #ifdef UNIX
  254.     SRANDOM((getpid() << 16) ^ time((long *) 0));
  255. #else
  256.     randomize();
  257. #endif
  258.   
  259. #if defined(__TURBOC__) || defined(__BORLANDC__)
  260.     /* Borland's library calls int10. Some vga mode utilities do not
  261.      * report the screen sizes correctly into the internal _video structure.
  262.      * This can cause the screen size to be faulty in the gettextinfo call.
  263.      * Instead, read the BIOS data area to get the correct screen info,
  264.      * and update the _video structure for later calls to
  265.      * gettextinfo(), clrscr(), etc... - WG7J
  266.      *
  267.      * If this doesn't work, you can now overwrite the values with
  268.      * the -r and -c command line options - WG7J
  269.      */
  270.     Numrows = (int) *(char far *)MK_FP(0x40,0x84) + 1;
  271.     gettextinfo(&PrevTi);
  272.     Numcols = PrevTi.screenwidth;
  273. #ifdef SPLITSCREEN
  274.     MainColors = PrevTi.attribute;
  275.     MainColors &= 0xf7; /* turn off highlite */
  276. #endif
  277. /*
  278.     Numrows = PrevTi.screenheight;
  279. */
  280.     if(Numrows == 1)
  281.         Numrows = 25;
  282.   
  283. #endif
  284.   
  285.     SwapMode = MEM_SWAP;
  286. #ifdef MSDOS
  287.     Screen = Screen_Address();
  288.   
  289.     /* If EMS is found, XMS is not used for swapping - WG7J */
  290. #ifdef EMS
  291.     if(ememavl(&emssize) == 0) {
  292.         EMS_Available = 1;
  293.         SwapMode = EMS_SWAP;
  294.     }
  295. #endif
  296.   
  297. #ifdef XMS
  298.     if((XMS_Available = Installed_XMS()) != 0)
  299. #ifdef EMS
  300.         if(!EMS_Available)
  301. #endif
  302.             SwapMode = XMS_SWAP;
  303. #endif
  304.   
  305. #endif /* MSDOS */
  306.   
  307.     while((c = getopt(argc,argv,"s:d:r:c:f:m:u:w:x:y:z:nbvelti")) != EOF){
  308.         switch(c){
  309. #ifdef  __TURBOC__
  310.             case 'b':       /* Use BIOS for screen output */
  311.                 directvideo = 0;
  312.                 break;
  313. #endif
  314.             case 'c':   /* Number of columns on screen */
  315.                 Numcols = atoi(optarg);
  316.                 break;
  317.             case 'd':   /* Root directory for various files */
  318.                 initroot(optarg);
  319.                 break;
  320.             case 'e':   /* Pause after error lines */
  321.                 ErrorPause = 1;
  322.                 break;
  323. #if defined(MSDOS) || defined(UNIX)
  324.             case 'f':
  325.                 assign_filenames(optarg);
  326.                 break;
  327. #endif
  328.             case 'i':
  329.                 ForceIndex = 1;
  330.                 break;
  331.             case 'l':   /* Don't remove mail locks */
  332.                 RmLocks = 0;
  333.                 break;
  334. #ifdef MSDOS
  335.             case 'm':   /* Swap mode, 0=EMS (default),1=XMS,2=MEM,3=FILE - WG7J */
  336.                 i = atoi(optarg);
  337. #ifdef XMS
  338.                 if(i == 1 && XMS_Available) {
  339.                     SwapMode = XMS_SWAP;
  340.                 } else
  341. #endif
  342.                     if(i == 2)
  343.                         SwapMode = MEM_SWAP;
  344.                     else if(i == 3)
  345.                         SwapMode = FILE_SWAP;
  346.                 break;
  347. #endif
  348. #ifdef TRACE
  349.             case 'n':
  350.                 Tracesession = 0; /* No session for tracing */
  351.                 break;
  352. #endif
  353.             case 'r':   /* Number of rows on screen */
  354.                 Numrows = atoi(optarg);
  355.                 break;
  356.             case 't':
  357.                 Step = 1;
  358.             /* note fallthrough */
  359. #ifdef STATUSWIN
  360.             case 'u':   /* No status lines */
  361.                 StatusLines = atoi(optarg);
  362.                 if(StatusLines > MAXSTATUSLINES)
  363.                     StatusLines = MAXSTATUSLINES;
  364.                 break;
  365. #endif
  366.             case 'v':
  367.                 Verbose = 1;
  368.                 break;
  369. #ifdef STATUSWIN
  370.         /* Color options - WG7J */
  371.             case 'w':
  372.                 GiveColor(optarg,&MainStColors);
  373.                 MainStColors |= 0x08; /* Turn on highlite, so it shows on b/w */
  374.                 break;
  375.             case 'x':
  376.                 GiveColor(optarg,&SesStColors);
  377.                 SesStColors |= 0x08; /* Turn on highlite, so it shows on b/w */
  378.                 break;
  379. #endif
  380. #ifdef SPLITSCREEN
  381.             case 'y':
  382.                 GiveColor(optarg,&MainColors);
  383.                 MainColors &= 0xf7; /* Turn off highlite, so high video shows! */
  384.                 textattr(MainColors);   /* Set the color for startup screen ! */
  385.                 break;
  386.             case 'z':
  387.                 GiveColor(optarg,&SplitColors);
  388.                 SplitColors |= 0x08;    /* Turn on higlite, so it shows on b/w */
  389.                 break;
  390. #endif
  391.         }
  392.     }
  393.   
  394. #if defined(__TURBOC__) || defined(__BORLANDC__)
  395.     /* Set the internal structure, in case there was a command
  396.      * line overwrite - WG7J
  397.      */
  398.     _video.screenheight = (unsigned char)Numrows;
  399.     _video.windowx2 = (unsigned char)(Numcols - 1);
  400.     _video.windowy2 = (unsigned char)(Numrows - 1);
  401. #endif
  402.   
  403.     ScreenSize = 2 * Numrows * Numcols;
  404.   
  405. #ifdef STATUSWIN
  406.     if(StatusLines > 1) {
  407. #ifdef MAILBOX
  408.         StBuf2 = mallocw(Numcols+3);
  409.         StLen2 = sprintf(StBuf2,"\r\nBBS:");
  410.         if(StatusLines > 2)
  411. #endif
  412.         {
  413.             StBuf3 = mallocw(Numcols+3);
  414.             sprintf(StBuf3,"\r\n");
  415.         }
  416.     }
  417. #endif
  418.   
  419. #ifdef MSDOS
  420. #ifdef XMS
  421.     if(XMS_Available)
  422.         /* Calculate space in kb for screen */
  423.         ScreenSizeK = (ScreenSize / 1024) + 1;
  424. #endif
  425. #endif
  426.   
  427.   
  428.     kinit();
  429.     ipinit();
  430.     ioinit();
  431.     Cmdpp = mainproc("cmdintrp");
  432.   
  433.     Sessions = (struct session *)callocw(Nsessions,sizeof(struct session));
  434. #ifdef TRACE
  435.     if(Tracesession)
  436.         Trace = newsession(NULLCHAR,TRACESESSION,0);
  437. #endif
  438.     Command = Lastcurr = newsession(NULLCHAR,COMMAND,0);
  439.     init_dirs(&dirs);
  440.     Command->curdirs=&dirs;
  441.   
  442.     /* Flow mode is set AFTER we've read the autoexec file !
  443.      * this keeps systems from locking up if the reboot is unattended - WG7J
  444.      */
  445. #ifndef LINUX
  446.     Display = newproc("display",250,display,0,NULLCHAR,NULL,0);
  447. #endif
  448.     tprintf(Nosversion,Version);
  449.     tputs(Version2);
  450.     tputs("Copyright 1991 by Phil Karn (KA9Q) and contributors.\n");
  451. #ifdef MSDOS
  452. #ifdef EMS
  453.     if(EMS_Available)
  454.         tputs("EMS detected.\n");
  455. #endif
  456. #ifdef XMS
  457.     if(XMS_Available)
  458.         tputs("XMS detected.\n");
  459. #endif
  460. #endif
  461.   
  462. #ifdef BETA
  463.     tputs("\007\007\007\n==> This is a BETA version; be warned ! <==\n\n");
  464. #endif
  465.   
  466.     rflush();
  467.   
  468.     /* Start background Daemons */
  469.     {
  470.         struct daemon *tp;
  471.   
  472.         for(tp=Daemons;;tp++){
  473.             if(tp->name == NULLCHAR)
  474.                 break;
  475.             newproc(tp->name,tp->stksize,tp->fp,0,NULLCHAR,NULL,0);
  476.         }
  477.     }
  478.   
  479.     if(optind < argc){
  480.         /* Read startup file named on command line */
  481.         if((fp = fopen(argv[optind],READ_TEXT)) == NULLFILE)
  482.             tprintf(NoRead,argv[optind],sys_errlist[errno]);
  483.     } else {
  484.         /* Read default startup file named in files.c (autoexec.nos) */
  485.         if((fp = fopen(Startup,READ_TEXT)) == NULLFILE)
  486.             tprintf(NoRead,Startup,sys_errlist[errno]);
  487.     }
  488.     if(fp != NULLFILE){
  489.         inbuf = mallocw(BUFSIZ);
  490.         intmp = mallocw(BUFSIZ);
  491.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  492.             strcpy(intmp,inbuf);
  493.             if(Verbose){
  494.                 tputs(intmp);
  495.                 rflush();
  496.             }
  497.             /* Are we stepping through autoexec.nos ? - WG7J */
  498.             if(Step) {
  499.                 int c;
  500.                 Command->ttystate.edit = Command->ttystate.echo = 0;
  501.                 c = toupper(keywait("Execute cmd ?",1));
  502.                 Command->ttystate.edit = Command->ttystate.echo = 1;
  503.                 if(c != 'Y')
  504.                     continue;
  505.             }
  506.             if(cmdparse(Cmds,inbuf,NULL) != 0){
  507.                 tprintf("input line: %s",intmp);
  508.                 if(ErrorPause)
  509.                     keywait(NULLCHAR,1);
  510.                 rflush();
  511.             }
  512.         }
  513.         fclose(fp);
  514.         free(inbuf);
  515.         free(intmp);
  516.     }
  517.   
  518.     /* Log that we started nos, but do this after the config file is read
  519.      * such that logging can be disabled - WG7J
  520.      */
  521.     log(-1,"JNOS %s was started",Version);
  522.   
  523.     /* Update .txt files that have old index files - WG7J */
  524.     UpdateIndex(NULL,ForceIndex);
  525.   
  526.     if(RmLocks)
  527.         RemoveMailLocks();
  528.   
  529.     Mprunning = 1;  /* we are on speed now */
  530.   
  531.     /* N7IPB - If lots of output generated during startup we have to wait
  532.      * for it all to be output before turning on 'more'
  533.      */
  534.     pause(1000);
  535.     Command->flowmode = 1;      /* set 'more' paging on command screen */
  536.   
  537.     /* Now loop forever, processing commands */
  538.     for(;;){
  539.         if(DosPrompt)
  540.             tprintf("%s ",dirs.dir);
  541.         if(!StatusLines)
  542.             tprintf("%lu ",coreleft());
  543.         tputs(Prompt);
  544.         usflush(Command->output);
  545.         if(recv_mbuf(Command->input,&bp,0,NULLCHAR,0) != -1){
  546.             logcmd(bp->data);
  547.             (void)cmdparse(Cmds,bp->data,Lastcurr);
  548.             free_p(bp);
  549.         }
  550.     }
  551. }
  552. /* Keyboard input process */
  553. /* Modified to support F-key session switching,
  554.  * from the WNOS3 sources - WG7J
  555.  */
  556. void
  557. keyboard(i,v1,v2)
  558. int i;
  559. void *v1;
  560. void *v2;
  561. {
  562.     int c;
  563.     struct mbuf *bp;
  564.     int j,k;
  565.     struct session *sp;
  566. #ifdef STATUSWIN
  567.     int newsession;
  568. #endif
  569.   
  570.     /* Keyboard process loop */
  571.     for(;;){
  572.         c = kbread();
  573. #ifdef STATUSWIN
  574.         newsession = 0;
  575. #endif
  576. #if(!defined(MSDOS) || defined(ESCAPE))
  577.         if(c == Escape && Escape != 0)
  578.             c = -2;
  579. #endif
  580.         if(c == -2 && Current != Command){
  581.             /* Save current tty mode and set cooked */
  582.             Lastcurr = Current;
  583.             Current = Command;
  584.             swapscreen(Lastcurr,Current);
  585. #ifdef STATUSWIN
  586.             newsession = 1;
  587. #endif
  588.             /* set 'more' paging on command screen */
  589.             Command->flowmode = 1;
  590.         }
  591.         if((c < -2) && (c > -12)) {             /* F1 to F9 pressed */
  592. #ifdef TRACE
  593.             /* If F9 is pressed, -11 is returned and we swap to Trace - WG7J */
  594.             if(c == -11 && Tracesession) {
  595.                 if(Current != Trace) {
  596.                     /* Save current tty mode and set cooked */
  597.                     swapscreen(Current,Trace);
  598.                     Lastcurr = Current;
  599.                     Current = Trace;
  600. #ifdef STATUSWIN
  601.                     newsession = 1;
  602. #endif
  603.                     /* turn off 'more' paging on trace screen */
  604.                     Trace->flowmode = 0;
  605.                 } else {
  606.                     /* Toggle back to previous session */
  607.                     Current = Lastcurr;
  608.                     Lastcurr = Trace;
  609.                     swapscreen(Lastcurr,Current);
  610. #ifdef STATUSWIN
  611.                     newsession = 1;
  612. #endif
  613.                 }
  614.             } else {
  615. #endif
  616.                 /* Swap directly to F-key session - WG7J */
  617.                 k = (-1 * c) - 2;
  618.                 for(sp = Sessions, j = 0; sp < &Sessions[Nsessions]; sp++) {
  619.                     if(sp->type == COMMAND)
  620.                         continue;
  621.                     j++;
  622.                     if(sp->type != FREE && j == k) {
  623.                         Lastcurr = Current;
  624.                         Current = sp;
  625.                         swapscreen(Lastcurr,Current);
  626. #ifdef STATUSWIN
  627.                         newsession = 1;
  628. #endif
  629.                         break;
  630.                     }
  631.                 }
  632. #ifdef TRACE
  633.             }
  634. #endif
  635.         }
  636. #ifdef STATUSWIN
  637.         if(newsession)
  638.             UpdateStatus();
  639. #endif
  640.         Current->row = Numrows - 1 - StatusLines;
  641.         psignal(&Current->row,1);
  642.         if(c >= 0){
  643. #ifdef LINUX
  644.             if (Current->morewait) /* end display pause, if any */
  645.                 Current->morewait = 2;
  646. #endif
  647.             /* If the screen driver was in morewait state, this char
  648.              * has woken him up. Toss it so it doesn't also get taken
  649.              * as normal input. If the char was a command escape,
  650.              * however, it will be accepted; this gives the user
  651.              * a way out of lengthy output.
  652.              */
  653.             if(!Current->morewait && (bp = ttydriv(Current,c)) != NULLBUF)
  654.                 send_mbuf(Current->input,bp,0,NULLCHAR,0);
  655.         }
  656.     }
  657. }
  658.   
  659. extern int Kblocked;
  660. extern char *Kbpasswd;
  661. #ifdef LOCK
  662.   
  663. /*Lock the keyboard*/
  664. int
  665. dolock(argc,argv,p)
  666. int argc;
  667. char *argv[];
  668. void *p;
  669. {
  670.   
  671.     extern char Noperm[];
  672.   
  673.     /*allow only keyboard users to access the lock command*/
  674.     if(Curproc->input != Command->input) {
  675.         tputs(Noperm);
  676.         return 0;
  677.     }
  678.     if(argc == 1) {
  679.         if(Kbpasswd == NULLCHAR)
  680.             tputs("Set password first\n");
  681.         else {
  682.             Kblocked = 1;
  683.             tputs("Keyboard locked\n");
  684.             Command->ttystate.echo = 0; /* Turn input echoing off! */
  685.         }
  686.         return 0;
  687.     }
  688.     if(argc == 3) {
  689.         if(*argv[1] == 'p') {   /*set the password*/
  690.             if(Kbpasswd != NULLCHAR){
  691.                 free(Kbpasswd);
  692.                 Kbpasswd = NULLCHAR;        /* reset the pointer */
  693.             }
  694.             if(!strlen(argv[2]))
  695.                 return 0;           /* clearing the buffer */
  696.             Kbpasswd = strdup(argv[2]);
  697.             return 0;
  698.         }
  699.     }
  700.   
  701.     tputs("Usage: lock password \"<unlock password>\"\n"
  702.     "or    'lock' to lock the keyboard\n");
  703.   
  704.     return 0;
  705. }
  706.   
  707. #endif
  708.   
  709. /*this is also called from the remote-server for the 'exit' command - WG7J*/
  710. void
  711. where_outta_here(resetme)
  712. int resetme;
  713. {
  714.     time_t StopTime;
  715.     FILE *fp;
  716.     char *inbuf,*intmp;
  717.   
  718.     /* Execute sequence of commands taken from file "~/onexit.nos" */
  719.     /* From iw0cnb */
  720.     if((fp = fopen(Onexit,READ_TEXT)) != NULLFILE){
  721.         inbuf = mallocw(BUFSIZ);
  722.         intmp = mallocw(BUFSIZ);
  723.         while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  724.             strcpy(intmp,inbuf);
  725.             if(Verbose){
  726.                 tputs(intmp);
  727.                 rflush();
  728.             }
  729.             if(cmdparse(Cmds,inbuf,NULL) != 0){
  730.                 tprintf("input line: %s",intmp);
  731.             }
  732.         }
  733.         fclose(fp);
  734.         free(inbuf);
  735.         free(intmp);
  736.     }
  737.     StopTime = time(&StopTime);
  738.     main_exit = TRUE;       /* let everyone know we're out of here */
  739.     reset_all();
  740.     if(Dfile_updater != NULLPROC)
  741.         alert(Dfile_updater,0); /* don't wait for timeout */
  742.     pause(3000);    /* Let it finish */
  743. #ifdef TRACE
  744.     shuttrace();
  745. #endif
  746.     log(-1,"JNOS was stopped");
  747. #ifdef LINUX
  748.     detach_all_asy();     /* make sure everything is unlocked */
  749.     pwait(NULL);
  750. #endif
  751.     iostop();
  752.     if(resetme)
  753. #ifdef LINUX
  754.     {
  755.         if (fork() == 0)
  756.             abort();
  757.         execvp(origargv[0], origargv); /* re-run NOS */
  758.     }
  759. #else
  760.     sysreset();
  761. #endif
  762. #ifdef MSDOS
  763. #ifdef EMS
  764.     effreeall();
  765. #endif
  766. #ifdef XMS
  767.     /* Free any possible XMS used for the screen */
  768.     Free_Screen_XMS();
  769. #endif
  770. #endif
  771.     window(1,1,Numcols,Numrows);
  772.     textattr(PrevTi.attribute);
  773.     clrscr();
  774.     exit(0);
  775. }
  776.   
  777. int
  778. doexit(argc,argv,p)
  779. int argc;
  780. char *argv[];
  781. void *p;
  782. {
  783.     time_t nowtime, elapsedtime;
  784.     unsigned int days,hrs,mins,secs;
  785.   
  786.     if(strnicmp(Curproc->name, "at ",3) == 0)   /* From the AT command */
  787.         where_outta_here(0);
  788.   
  789.     if(Curproc->input == Command->input) {  /* From keyboard */
  790.         Command->ttystate.edit = Command->ttystate.echo = 0;
  791.         if(toupper(keywait("Are you sure? ",0))=='Y') {
  792.             nowtime = time(&nowtime);                       /* current time */
  793.             elapsedtime = nowtime - StartTime;              /* nos elapsed time */
  794.             secs = (unsigned int)(elapsedtime % 60);
  795.             elapsedtime = elapsedtime / 60;
  796.             mins = (unsigned int)(elapsedtime % 60);
  797.             elapsedtime = elapsedtime / 60;
  798.             hrs = (unsigned int)(elapsedtime % 24);
  799.             elapsedtime = elapsedtime / 24;
  800.             days = (unsigned int) elapsedtime;
  801.             tprintf("JNOS Exiting - Runtime => %u days:%02u hours:%02u minutes:%02u seconds.\n",days,hrs,mins,secs);
  802.             where_outta_here(0); /*No reset!*/
  803.         }
  804.         Command->ttystate.edit = Command->ttystate.echo = 1;
  805.         return 0;
  806.     }
  807.    /* Anything else; probably mailbox-sysop */
  808.     return -2;
  809. }
  810.   
  811. extern char Chostname[];
  812.   
  813. int
  814. dohostname(argc,argv,p)
  815. int argc;
  816. char *argv[];
  817. void *p;
  818. {
  819. #ifdef CONVERS
  820.     char *cp;
  821. #endif
  822.   
  823.     if(argc < 2)
  824.         tprintf("%s\n",Hostname);
  825.     else {
  826.         struct iface *ifp;
  827.         char *name;
  828.   
  829.         if((ifp = if_lookup(argv[1])) != NULLIF){
  830.             if((name = resolve_a(ifp->addr, FALSE)) == NULLCHAR){
  831.                 tputs("Interface address not resolved\n");
  832.                 return 1;
  833.             } else {
  834.                 if(Hostname != NULLCHAR)
  835.                     free(Hostname);
  836.                 Hostname = name;
  837.                 tprintf("Hostname set to %s\n", name );
  838.             }
  839.         } else {
  840.             if(Hostname != NULLCHAR)
  841.                 free(Hostname);
  842.             Hostname = strdup(argv[1]);
  843.             /* Remove trailing dot */
  844.             if(Hostname[strlen(Hostname)] == '.')
  845.                 Hostname[strlen(Hostname)] = '.';
  846.         }
  847. #ifdef CONVERS
  848.     /* If convers hostname not set yet, set it to first 10 chars
  849.      * of the hostname. If there are '.' from the right, cut off
  850.      * before that. - WG7J
  851.      */
  852.         if(Chostname[0] == '\0') {
  853.             strncpy(Chostname,Hostname,CNAMELEN);
  854.             if((cp = strrchr(Chostname,'.')) != NULLCHAR)
  855.                 *cp = '\0';
  856.         }
  857. #endif
  858.     }
  859.     return 0;
  860. }
  861.   
  862. int Uselog = 1;
  863.   
  864. int
  865. dolog(argc,argv,p)
  866. int argc;
  867. char *argv[];
  868. void *p;
  869. {
  870.     return setbool(&Uselog,"disk logging",argc,argv);
  871. }
  872.  
  873.   
  874. void log(int s,char *fmt, ...)
  875. {
  876.     va_list ap;
  877.     char *cp, ML[FILE_PATH_SIZE];
  878.     time_t t;
  879.     int i;
  880.     struct sockaddr fsocket;
  881.     FILE *fp;
  882.   
  883.     if(!Uselog)
  884.         return;
  885.   
  886.     time(&t);
  887.     cp = ctime(&t);
  888.   
  889.     sprintf(ML,"%s/%2.2s%3.3s%2.2s",LogsDir,cp+8,cp+4,cp+22);
  890.     if ((fp = fopen(ML,APPEND_TEXT)) == NULLFILE)
  891.         return;
  892.   
  893.     i = SOCKSIZE;
  894.   
  895.     fprintf(fp,"%9.9s",cp+11);
  896.     if(getpeername(s,(char *)&fsocket,&i) != -1)
  897.         fprintf(fp, " %s",psocket(&fsocket));
  898.     fprintf(fp, " - ");
  899.     va_start(ap,fmt);
  900.     vfprintf(fp,fmt,ap);
  901.     va_end(ap);
  902.     fprintf(fp,"\n");
  903.     fclose(fp);
  904. }
  905.   
  906. int
  907. dohelp(argc,argv,p)
  908. int argc;
  909. char *argv[];
  910. void *p;
  911. {
  912.     register struct cmds *cmdp;
  913.     int i;
  914.     char buf[FILE_PATH_SIZE];
  915.     char **pargv;
  916.     FILE *fp;
  917.     struct mbx *m;
  918.   
  919. /* ?  => display compiled-command names 
  920.  * help   =or=   help ?  => show /help/help
  921.  * help X => show /help/X
  922.  */
  923.     if(*argv[0] == '?' ) {
  924.         tputs("Main commands:\n");
  925.         memset(buf,' ',sizeof(buf));
  926.         buf[75] = '\n';
  927.         buf[76] = '\0';
  928.         for(i=0,cmdp = Cmds;cmdp->name != NULL;cmdp++,i = (i+1)%5){
  929.             strncpy(&buf[i*15],cmdp->name,strlen(cmdp->name));
  930.             if(i == 4){
  931.                 tputs(buf);
  932.                 memset(buf,' ',sizeof(buf));
  933.                 buf[75] = '\n';
  934.                 buf[76] = '\0';
  935.             }
  936.         }
  937.         if(i != 0)
  938.             tputs(buf);
  939.     } else {
  940.         sprintf(buf,"%s/%s",CmdsHelpdir,"help");  /* default */
  941.         if(argc > 1) {
  942.             for(i=0; Cmds[i].name != NULLCHAR; ++i)
  943.                 if(!strncmp(Cmds[i].name,argv[1],strlen(argv[1]))) {
  944.                     if(*argv[1] != '?')
  945.                         sprintf(buf,"%s/%s",CmdsHelpdir,Cmds[i].name);
  946.                     break;
  947.                 }
  948.             if(Cmds[i].name == NULLCHAR) {
  949.                 tputs("Unknown command; type \"?\" for list\n");
  950.                 return 0;
  951.             }
  952.         }
  953. #if defined MORESESSION || defined DIRSESSION || defined FTPSESSION
  954.         pargv = (char **)callocw(2,sizeof(char *));
  955.         pargv[1] = strdup(buf);
  956.         if(Curproc->input == Command->input) {   /* from console? */
  957.             newproc("more",512,(void (*)__ARGS((int,void *,void *)))morecmd,2,(void *)pargv,p,1);
  958.         } else {
  959.             morecmd(2,pargv,p);
  960.             free(pargv[1]);
  961.             free(pargv);
  962.         }
  963. #else
  964.         if((fp = fopen(buf,READ_TEXT)) == NULLFILE)
  965.             tprintf(NoRead,buf,sys_errlist[errno]);
  966.         else {
  967.             for (m=Mbox; m!=NULLMBX; m=m->next)
  968.                 if (m->proc == Curproc) break;
  969.             sendfile(fp,Curproc->output,ASCII_TYPE,0,m);
  970.             fclose(fp);
  971.         }
  972. #endif
  973.     }
  974.     return 0;
  975. }
  976.   
  977. /* Attach an interface
  978.  * Syntax: attach <hw type> <I/O address> <vector> <mode> <label> <bufsize> [<speed>]
  979.  */
  980. int
  981. doattach(argc,argv,p)
  982. int argc;
  983. char *argv[];
  984. void *p;
  985. {
  986.     return subcmd(Attab,argc,argv,p);
  987. }
  988. /* Manipulate I/O device parameters */
  989. int
  990. doparam(argc,argv,p)
  991. int argc;
  992. char *argv[];
  993. void *p;
  994. {
  995.     int param,set;
  996.     int32 val;
  997.     register struct iface *ifp;
  998.   
  999.     if((ifp = if_lookup(argv[1])) == NULLIF){
  1000.         tprintf(Badinterface,argv[1]);
  1001.         return 1;
  1002.     }
  1003.     if(ifp->ioctl == NULL){
  1004.         tputs("Not supported\n");
  1005.         return 1;
  1006.     }
  1007.     if(argc < 3){
  1008.         for(param=1;param<=16;param++){
  1009.             val = (*ifp->ioctl)(ifp,param,FALSE,0L);
  1010.             if(val != -1)
  1011.                 tprintf("%s: %ld\n",parmname(param),val);
  1012.         }
  1013.         return 0;
  1014.     }
  1015.     param = devparam(argv[2]);
  1016.     if(param == -1){
  1017.         tprintf("Unknown parameter %s\n",argv[2]);
  1018.         return 1;
  1019.     }
  1020.     if(argc < 4){
  1021.         set = FALSE;
  1022.         val = 0L;
  1023.     } else {
  1024.         set = TRUE;
  1025.         val = atol(argv[3]);
  1026.     }
  1027.     val = (*ifp->ioctl)(ifp,param,set,val);
  1028.     if(val == -1){
  1029.         tprintf("Parameter %s not supported\n",argv[2]);
  1030.     } else {
  1031.         tprintf("%s: %ld\n",parmname(param),val);
  1032.     }
  1033.     return 0;
  1034. }
  1035.   
  1036. /* Display or set IP interface control flags */
  1037. int
  1038. domode(argc,argv,p)
  1039. int argc;
  1040. char *argv[];
  1041. void *p;
  1042. {
  1043.     register struct iface *ifp;
  1044.   
  1045.     if((ifp = if_lookup(argv[1])) == NULLIF){
  1046.         tprintf(Badinterface,argv[1]);
  1047.         return 1;
  1048.     }
  1049.     if(argc < 3){
  1050.         tprintf("%s: %s\n",ifp->name,
  1051.         (ifp->flags & CONNECT_MODE) ? "VC mode" : "Datagram mode");
  1052.         return 0;
  1053.     }
  1054.     switch(argv[2][0]){
  1055.         case 'v':
  1056.         case 'c':
  1057.         case 'V':
  1058.         case 'C':
  1059.             ifp->flags |= CONNECT_MODE;
  1060.             break;
  1061.         case 'd':
  1062.         case 'D':
  1063.             ifp->flags &= ~CONNECT_MODE;
  1064.             break;
  1065.         default:
  1066.             tprintf("Usage: %s [vc | datagram]\n",argv[0]);
  1067.             return 1;
  1068.     }
  1069.     return 0;
  1070. }
  1071.   
  1072. #if     (!defined(MSDOS) || defined(ESCAPE))
  1073. int
  1074. doescape(argc,argv,p)
  1075. int argc;
  1076. char *argv[];
  1077. void *p;
  1078. {
  1079.     if(argc < 2)
  1080.         tprintf("0x%x\n",Escape);
  1081.     else
  1082.         Escape = *argv[1];
  1083.     return 0;
  1084. }
  1085. #endif  MSDOS
  1086.   
  1087.   
  1088. #ifdef REMOTESERVER
  1089. extern char *Rempass;   /* Remote access password */
  1090. char remote_options[] = "a:p:k:s:";
  1091. #else
  1092. char remote_options[] = "a:p:k:";
  1093. #endif
  1094.   
  1095. /* Generate system command packet. Synopsis:
  1096.  * remote [-p port#] [-k key] [-a hostname] <hostname> reset|exit|kickme
  1097.  */
  1098. int
  1099. doremote(argc,argv,p)
  1100. int argc;
  1101. char *argv[];
  1102. void *p;
  1103. {
  1104.     struct sockaddr_in fsock;
  1105.     int s,c;
  1106.     char *data,x;
  1107.     int16 port,len;
  1108.     char *key = NULLCHAR;
  1109.     int klen;
  1110.     int32 addr = 0;
  1111.     char *cmd,*host;
  1112.   
  1113.     port = IPPORT_REMOTE;   /* Set default */
  1114.     optind = 1;             /* reinit getopt() */
  1115.     while((c = getopt(argc,argv,remote_options)) != EOF){
  1116.         switch(c){
  1117.             case 'a':
  1118.                 if((addr = resolve(optarg)) == 0){
  1119.                     tprintf(Badhost,optarg);
  1120.                     return -1;
  1121.                 }
  1122.                 break;
  1123.             case 'p':
  1124.                 port = atoi(optarg);
  1125.                 break;
  1126.             case 'k':
  1127.                 key = optarg;
  1128.                 klen = strlen(key);
  1129.                 break;
  1130. #ifdef REMOTESERVER
  1131.             case 's':
  1132.                 Rempass = strdup(optarg);
  1133.                 return 0;       /* Only set local password */
  1134. #endif
  1135.         }
  1136.     }
  1137.     if(optind > argc - 2){
  1138.         tputs("Insufficient args\n");
  1139.         return -1;
  1140.     }
  1141.     host = argv[optind++];
  1142.     cmd = argv[optind];
  1143.     if((s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  1144.         tputs("socket failed\n");
  1145.         return 1;
  1146.     }
  1147.     len = 1;
  1148.     /* Did the user include a password or kickme target? */
  1149.     if(addr != 0 && cmd[0] == 'k')
  1150.         len += sizeof(int32);
  1151.   
  1152.     if(key != NULLCHAR && (cmd[0] == 'r' || cmd[0] == 'e'))
  1153.         len += klen;
  1154.   
  1155.     if(len == 1)
  1156.         data = &x;
  1157.     else
  1158.         data = mallocw(len);
  1159.   
  1160.     fsock.sin_family = AF_INET;
  1161.     if((fsock.sin_addr.s_addr = resolve(host)) == 0){
  1162.         tprintf(Badhost,host);
  1163.         goto cleanup;
  1164.     }
  1165.     fsock.sin_port = port;
  1166.   
  1167.     switch(cmd[0]){
  1168.         case 'r':
  1169.             data[0] = SYS_RESET;
  1170.             if(key != NULLCHAR)
  1171.                 strncpy(&data[1],key,klen);
  1172.             break;
  1173.         case 'e':
  1174.             data[0] = SYS_EXIT;
  1175.             if(key != NULLCHAR)
  1176.                 strncpy(&data[1],key,klen);
  1177.             break;
  1178.         case 'k':
  1179.             data[0] = KICK_ME;
  1180.             if(addr != 0)
  1181.                 put32(&data[1],addr);
  1182.             break;
  1183.         default:
  1184.             tprintf("Unknown command %s\n",cmd);
  1185.             goto cleanup;
  1186.     }
  1187.     /* Form the command packet and send it */
  1188.     if(sendto(s,data,len,0,(char *)&fsock,sizeof(fsock)) == -1){
  1189.         tprintf("sendto failed: %s\n",sys_errlist[errno]);
  1190.         goto cleanup;
  1191.     }
  1192.     cleanup:
  1193.     if(data != &x)
  1194.         free(data);
  1195.     close_s(s);
  1196.     return 0;
  1197. }
  1198.   
  1199. #if defined MORESESSION || defined DIRSESSION || defined FTPSESSION
  1200.   
  1201. int
  1202. morecmd(argc,argv,p)
  1203. int argc;
  1204. char *argv[];
  1205. void *p;
  1206. {
  1207.     struct session *sp;
  1208.     FILE *fp;
  1209.     char buf[81],fname[128];
  1210.     int row;
  1211.     int usesession = 0;
  1212.   
  1213.     /* Use a session if this comes from console - WG7J*/
  1214.     if(Curproc->input == Command->input) {
  1215.         usesession = 1;
  1216.         if((sp = newsession(argv[1],MORE,0)) == NULLSESSION){
  1217.             return 1;
  1218.         }
  1219.         /* Put tty into raw mode so single-char responses will work */
  1220.         sp->ttystate.echo = sp->ttystate.edit = 0;
  1221.         row = Numrows - 1 - StatusLines;
  1222.     }
  1223.   
  1224.     strcpy(fname,make_fname(Command->curdirs->dir,argv[1]));
  1225.     if((fp = fopen(fname,READ_TEXT)) == NULLFILE){
  1226.         tprintf(NoRead,fname,sys_errlist[errno]);
  1227.         if(usesession) {
  1228.             keywait(NULLCHAR,1);
  1229.             freesession(sp);
  1230.         }
  1231.         return 1;
  1232.     }
  1233.     while(fgets(buf,sizeof(buf),fp),!feof(fp)){
  1234.         if((argc < 3) || (strstr(buf,argv[2])!=NULLCHAR)) {
  1235.             tputs(buf);
  1236.             if(usesession) {
  1237.                 if(--row == 0){
  1238.                     row = keywait(TelnetMorePrompt,0);
  1239.                     switch(row){
  1240.                         case -1:
  1241.                         case 'q':
  1242.                         case 'Q':
  1243.                             goto done;
  1244.                         case '\n':
  1245.                         case '\r':
  1246.                             row = 1;
  1247.                             break;
  1248.                         case ' ':
  1249.                         default:
  1250.                             row = Numrows - 1 - StatusLines;
  1251.                     }
  1252.                 }
  1253.             }
  1254.         }
  1255.     }
  1256.     done:   fclose(fp);
  1257.     if(usesession) {
  1258.         keywait(NULLCHAR,1);
  1259.         freesession(sp);
  1260.     }
  1261.     return 0;
  1262. }
  1263. #endif /* MORE | DIR | FTP SESSION */
  1264.   
  1265. #ifdef MORESESSION
  1266. int
  1267. domore(argc,argv,p)
  1268. int argc;
  1269. char *argv[];
  1270. void *p;
  1271. {
  1272.     char **pargv;
  1273.     int i;
  1274.   
  1275.     if(Curproc->input == Command->input) {
  1276.         /* Make private copy of argv and args,
  1277.          * spawn off subprocess and return.
  1278.          */
  1279.         pargv = (char **)callocw(argc,sizeof(char *));
  1280.         for(i=0;i<argc;i++)
  1281.             pargv[i] = strdup(argv[i]);
  1282.         newproc("more",512,(void (*)__ARGS((int,void *,void *)))morecmd,argc,(void *)pargv,p,1);
  1283.     } else
  1284.         morecmd(argc,argv,p);
  1285.     return 0;
  1286. }
  1287. #endif /* MORESESSION */
  1288.   
  1289. #ifdef ALLCMD
  1290. int
  1291. dotaillog(argc,argv,p)
  1292. int argc;
  1293. char *argv[];
  1294. void *p;
  1295. {
  1296.     char logfile[129];
  1297.     time_t t;
  1298.     char *cp;
  1299.   
  1300.     /* Create the log file name */
  1301.     time(&t);
  1302.     cp = ctime(&t);
  1303.     sprintf(logfile,"%s/%2.2s%3.3s%2.2s",LogsDir,cp+8,cp+4,cp+22);
  1304.   
  1305.     argc = 2;   /* ignore any provided args */
  1306.     argv[1] = logfile;
  1307.     return dotail(argc,argv,p);
  1308. }
  1309.   
  1310. int
  1311. dotail(argc,argv,p)
  1312. int argc;
  1313. char *argv[];
  1314. void *p;
  1315. {
  1316.     register int handle, i;
  1317.     register unsigned line = 0, rdsize = 2000;
  1318.     long length;
  1319.     char *buffer;
  1320.   
  1321.     buffer = callocw(2000, sizeof (char));
  1322.   
  1323.     if ((handle = open (argv[1], O_BINARY | O_RDONLY)) == -1) {
  1324.         tprintf(NoRead,argv[1],sys_errlist[errno]);
  1325.         free(buffer);
  1326.         return -1;
  1327.     }
  1328.     length = filelength(handle);
  1329.   
  1330.     if (length > 2000) {
  1331.         length -= 2000;
  1332.     } else {
  1333.         rdsize = (int) length;
  1334.         length = 0;
  1335.     }
  1336.   
  1337.     lseek (handle, length, SEEK_SET);
  1338.     if (read (handle, buffer, rdsize) == -1) {
  1339.         tprintf(NoRead,argv[1],sys_errlist[errno]);
  1340.         close(handle);
  1341.         free(buffer);
  1342.         return -1;
  1343.     }
  1344.   
  1345.     for (i = rdsize - 1; i > 0; i--) {
  1346.         if (buffer[i] == '\n')
  1347.             line++;
  1348.         if (line == 18)
  1349.             break;
  1350.     }
  1351.     for (; i < rdsize; i++)
  1352.         tputc(buffer[i]);
  1353.   
  1354.     tputc('\n');
  1355.     close(handle);
  1356.     free(buffer);
  1357.     return 0;
  1358. }
  1359. #endif /*ALLCMD*/
  1360.   
  1361. /* No-op command */
  1362. int
  1363. donothing(argc,argv,p)
  1364. int argc;
  1365. char *argv[];
  1366. void *p;
  1367. {
  1368.     return 0;
  1369. }
  1370.  
  1371. /* Pause command */  
  1372. int
  1373. dopause(argc,argv,p)
  1374. int argc;
  1375. char *argv[];
  1376. void *p;
  1377. {
  1378.     int secs;
  1379.  
  1380.     if(argc > 1) {
  1381.         secs = atoi(argv[1]);
  1382.         if (secs > 0) pause(1000L * secs);
  1383.     }
  1384.     return 0;
  1385. }
  1386.  
  1387. #ifdef MAILERROR
  1388. static int SendError = 1;
  1389.   
  1390. int doerror(int argc,char *argv[],void *p) {
  1391.     return setbool(&SendError,"Mail errors",argc,argv);
  1392. }
  1393.   
  1394. /* Mail a system message to the sysop - WG7J */
  1395. void
  1396. mail_error(char *fmt, ...)
  1397. {
  1398.     FILE *wrk,*txt;
  1399.     va_list ap;
  1400.     char *cp;
  1401.     long t,msgid;
  1402.     char fn[128];
  1403.   
  1404.     if(!SendError)
  1405.         return;
  1406.   
  1407.     /* Get current time */
  1408.     time(&t);
  1409.   
  1410.     /* get the message id for this message */
  1411.     msgid = get_msgid();
  1412.   
  1413.     /* Create the smtp work file */
  1414.     sprintf(fn,"%s/%ld.wrk",Mailqdir,msgid);
  1415.     if((wrk = fopen(fn,"w")) == NULL)
  1416.         return;
  1417.   
  1418.      /* Create the smtp text file */
  1419.     sprintf(fn,"%s/%ld.txt",Mailqdir,msgid);
  1420.     if((txt = fopen(fn,"w")) == NULL) {
  1421.         fclose(wrk);
  1422.         return;
  1423.     }
  1424.   
  1425.     /* Fill in the work file */
  1426.     fprintf(wrk,"%s\nMAILER-DAEMON@%s\nsysop@%s",Hostname,Hostname,Hostname);
  1427.     fclose(wrk);
  1428.   
  1429.     /* Fill in the text file headers */
  1430.     fprintf(txt,"%s%s",Hdrs[DATE],ptime(&t));
  1431.     fprintf(txt,"%s<%ld@%s>\n",Hdrs[MSGID],msgid,Hostname);
  1432.     fprintf(txt,"%sMAILER-DAEMON@%s\n",Hdrs[FROM],Hostname);
  1433.     fprintf(txt,"%ssysop@%s\n",Hdrs[TO],Hostname);
  1434.     fprintf(txt,"%sSystem message\n\n",Hdrs[SUBJECT]);
  1435.   
  1436.     /* Print the text body */
  1437.     cp = ctime(&t);
  1438.     fprintf(txt,"On %s",cp);
  1439.     va_start(ap,fmt);
  1440.     vfprintf(txt,fmt,ap);
  1441.     va_end(ap);
  1442.     fputc('\n',txt);
  1443.     fclose(txt);
  1444.   
  1445.     /* Now kick the smtp server */
  1446.     smtptick(NULL);
  1447. }
  1448. #endif /* MAILERROR */
  1449.   
  1450. int
  1451. dosource(argc,argv,p)
  1452. int argc;
  1453. char *argv[];
  1454. void *p;
  1455. {
  1456.     int linenum = 0;
  1457.     char *inbuf,*intmp;
  1458.     FILE *fp;
  1459.   
  1460.     /* Read command source file */
  1461.     if((fp = fopen(argv[1],READ_TEXT)) == NULLFILE){
  1462.         tprintf(NoRead,argv[1],sys_errlist[errno]);
  1463.         return 1;
  1464.     }
  1465.   
  1466.     inbuf = malloc(BUFSIZ);
  1467.     intmp = malloc(BUFSIZ);
  1468.     while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
  1469.         strcpy(intmp,inbuf);
  1470.         linenum++;
  1471.         if(Verbose)
  1472.             tputs(intmp);
  1473.         if(cmdparse(Cmds,inbuf,NULL) != 0){
  1474.             tprintf("*** file \"%s\", line %d: %s\n",
  1475.             argv[1],linenum,intmp);
  1476.         }
  1477.     }
  1478.     fclose(fp);
  1479.     free(inbuf);
  1480.     free(intmp);
  1481.     return 0;
  1482. }
  1483.   
  1484. #ifdef TTYLINKSERVER
  1485. /* if unattended mode is set - restrict ax25, telnet and maybe other sessions */
  1486. int
  1487. doattended(argc,argv,p)
  1488. int argc;
  1489. char *argv[];
  1490. void *p;
  1491. {
  1492.     return setbool(&Attended,"Attended flag",argc,argv);
  1493. }
  1494. #endif
  1495.   
  1496. /* if ThirdParty is not set - restrict the mailbox (S)end command to local only */
  1497. int
  1498. dothirdparty(argc,argv,p)
  1499. int argc;
  1500. char *argv[];
  1501. void *p;
  1502. {
  1503.     return setbool(&ThirdParty,"Third-Party mail flag",argc,argv);
  1504. }
  1505.   
  1506. #ifdef ALLCMD
  1507. int
  1508. domdump(argc,argv,p)
  1509. int argc;
  1510. char *argv[];
  1511. void *p;
  1512. {
  1513.     unsigned int i;
  1514.     char *addr,*cp;
  1515.     unsigned int segment,offset;
  1516.     unsigned int len = 8 * 16;      /* default is 8 lines of hex dump */
  1517.   
  1518.     if(argc < 2 || argc > 3) {
  1519.         tputs("Usage:- dump <hex-address | .> [decimal-range] \n");
  1520.         return 0;
  1521.     }
  1522.     if(argv[1][0] == '.')
  1523.         addr = DumpAddr;                /* Use last end address */
  1524.     else {
  1525.         if((cp=strchr(argv[1],':')) != NULL) {
  1526.             /* Interpret segment:offset notation */
  1527.             *cp++ = '\0';
  1528.             segment = (unsigned int) htol(argv[1]);
  1529.             offset = (unsigned int) htol(cp);
  1530.             addr = MK_FP(segment,offset);
  1531.         } else
  1532.             addr = ltop(htol(argv[1]));     /* get address of item being dumped */
  1533.     }
  1534.   
  1535.     if(argc == 3) {
  1536.         len = atoi(argv[2]);
  1537.         len = ((len + 15) >> 4) << 4;   /* round up to modulo 16 */
  1538.     }
  1539.   
  1540.     if(len < 1 || len > 256) {
  1541.         tputs("Invalid dump range. Valid is 1 to 256\n");
  1542.         return 0;
  1543.     }
  1544.     tprintf("            Main Memory Dump Of Location %Fp\n", addr);
  1545.     tputs("Addr (offset)           Hexadecimal                         Ascii\n");
  1546.     tputs("----                    -----------                         -----\n\n");
  1547.   
  1548.     for(i = 0; i < len; i += 16)
  1549.         fmtline(i, (char *)(addr + i), 16);
  1550.     DumpAddr = (char *)(addr + i);          /* update address */
  1551.     return 0;
  1552. }
  1553.   
  1554. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  1555.  * translation, e.g.,
  1556.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  1557.  */
  1558. static void
  1559. fmtline(addr,buf,len)
  1560. int16 addr;
  1561. char *buf;
  1562. int16 len;
  1563. {
  1564.     char line[81];
  1565.     register char *aptr,*cptr;
  1566.     register char c;
  1567.   
  1568.     memset(line,' ',sizeof(line));
  1569.     ctohex(line,(int16)hibyte(addr));
  1570.     ctohex(line+2,(int16)lobyte(addr));
  1571.     aptr = &line[6];
  1572.     cptr = &line[55];
  1573.     while(len-- != 0){
  1574.         c = *buf++;
  1575.         ctohex(aptr,(int16)uchar(c));
  1576.         aptr += 3;
  1577.         c &= 0x7f;
  1578.         if((c > 0x1f) && (c < 0x7f))
  1579.             *cptr++ = c;
  1580.         else
  1581.             *cptr++ = '.';
  1582.     }
  1583.     *cptr++ = '\0';
  1584.     tprintf("%s\n",line);
  1585. }
  1586. /* Convert byte to two ascii-hex characters */
  1587. static void
  1588. ctohex(buf,c)
  1589. register char *buf;
  1590. register int16 c;
  1591. {
  1592.     static char hex[] = "0123456789abcdef";
  1593.   
  1594.     *buf++ = hex[hinibble(c)];
  1595.     *buf = hex[lonibble(c)];
  1596. }
  1597. #endif
  1598.   
  1599. int
  1600. dowrite(argc,argv,p)
  1601. int argc;
  1602. char *argv[];
  1603. void *p;
  1604. {
  1605.     int s;
  1606.     struct mbx *m;
  1607.   
  1608.     if((s = atoi(argv[1])) == 0) { /* must be a name */
  1609. #ifdef MAILBOX
  1610.         /* check the mailbox users */
  1611.         for(m=Mbox;m;m=m->next){
  1612.             if(!stricmp(m->name,argv[1]))
  1613.                 break;
  1614.         }
  1615.         if(!m)
  1616.             return 0;
  1617.         s = m->user;
  1618. #else
  1619.         return 0;
  1620. #endif
  1621.     }
  1622.     usprintf(s,"*** Msg from SYSOP: %s\n",argv[2]);
  1623.     usflush(s);
  1624.   
  1625.     return 0;
  1626. }
  1627.   
  1628. #ifdef MAILBOX
  1629. /* write a message to all nodeshell users
  1630.  * argv[1] is the message.
  1631.  */
  1632. int
  1633. dowriteall(argc,argv,p)
  1634. int argc;
  1635. char *argv[];
  1636. void *p;
  1637. {
  1638.     struct mbx *m;
  1639.   
  1640.     for(m=Mbox;m;m=m->next){
  1641.         if(m->sid & MBX_SID)
  1642.             continue;
  1643.         usprintf(m->user,"*** Msg from SYSOP: %s\n",argv[1]);
  1644.         usflush(m->user);
  1645.     }
  1646.     return 0;
  1647. }
  1648. #endif
  1649.   
  1650.   
  1651. int
  1652. dostatus(argc,argv,p)
  1653. int argc;
  1654. char *argv[];
  1655. void *p;
  1656. {
  1657.     time_t nowtime, elapsedtime, nosseconds;
  1658.     unsigned int days,hrs,mins,secs;
  1659.   
  1660.     nowtime = time(&nowtime);                       /* current time */
  1661.     nosseconds = secclock();            /* Current NOS lifetime */
  1662.     elapsedtime = nowtime - StartTime;              /* nos elapsed time */
  1663.   
  1664.     tprintf(Nosversion,Version);
  1665.     tputs(Version2);
  1666.     tprintf("Tty: %d rows, %d columns\n",Numrows,Numcols);
  1667.   
  1668. #ifdef  MSDOS
  1669.     tprintf(NosLoadInfo, _CS, _DS);
  1670. #endif
  1671.     tprintf("\nThe system time is %s", ctime(&nowtime));
  1672.     tprintf("NOS was started on %s\n", ctime(&StartTime));
  1673.     secs = (unsigned int) (elapsedtime % 60);
  1674.     elapsedtime = elapsedtime / 60;
  1675.     mins = (unsigned int) (elapsedtime % 60);
  1676.     elapsedtime = elapsedtime / 60;
  1677.     hrs = (unsigned int) (elapsedtime % 24);
  1678.     elapsedtime = elapsedtime / 24;
  1679.     days = (unsigned int) elapsedtime;
  1680.     tprintf("Elapsed time => %u days:%02u hours:%02u minutes:%02u seconds.\n", days,hrs,mins,secs);
  1681.     if(nosseconds < elapsedtime)
  1682.         tprintf("NOS has lost %lu seconds in missed clock ticks!\n", \
  1683.         elapsedtime - nosseconds);
  1684.     tputc('\n');
  1685. #ifdef TTYLINKSERVER
  1686.     tprintf("The station is currently %sttended.\n", Attended ? "A" : "Una");
  1687. #endif
  1688. #ifdef ALLCMD
  1689.     tputs("The 'Message Of The Day' is ");
  1690.     if(Motd != NULLCHAR)
  1691.         tprintf("\n%s",Motd);
  1692.     else
  1693.         tputs("not set!\n");
  1694. #endif
  1695. #ifdef  __TURBOC__
  1696.     dofstat();              /* print status of open files */
  1697. #endif
  1698.     return 0;
  1699. }
  1700.   
  1701. #ifdef ALLCMD
  1702. int
  1703. domotd(argc,argv,p)
  1704. int argc;
  1705. char *argv[];
  1706. void *p;
  1707. {
  1708.     if(argc > 2) {
  1709.         tputs("Usage: motd \"<your message>\"\n");
  1710.         return 1;
  1711.     }
  1712.   
  1713.     if(argc < 2) {
  1714.         if(Motd != NULLCHAR)
  1715.             tputs(Motd);
  1716.     } else {
  1717.         if(Motd != NULLCHAR){
  1718.             free(Motd);
  1719.             Motd = NULLCHAR;                /* reset the pointer */
  1720.         }
  1721.   
  1722.         if(!strlen(argv[1]))
  1723.             return 0;                       /* clearing the buffer */
  1724.   
  1725.         Motd = mallocw(strlen(argv[1])+5);      /* allow for the EOL char etc */
  1726.         strcpy(Motd, argv[1]);
  1727.         strcat(Motd, "\n");                     /* add the EOL char */
  1728.     }
  1729.     return 0;
  1730. }
  1731. #endif /*ALLCMD*/
  1732.   
  1733. #ifdef  __TURBOC__
  1734. /*
  1735.  * Fstat utility code.
  1736.  * Converted to go into NOS by Kelvin Hill - G1EMM  April 9, 1990
  1737.  */
  1738.   
  1739. extern unsigned char _osmajor;
  1740.   
  1741. static char    *localcopy(char far *);
  1742. static char    *progname(unsigned int);
  1743.   
  1744. #ifdef __TURBOC__
  1745.   
  1746. extern char *Taskers[];
  1747. extern int Mtasker;
  1748.   
  1749. int
  1750. dofstat()
  1751. {
  1752.     union REGS regs;
  1753.     struct SREGS segregs;
  1754.     char far *pfiletab, far * pnext, far * fp;
  1755.     char far *name, file[13], far * plist, far * entry;
  1756.     char ownername[9], ownerext[5];
  1757.     int nfiles, i, j, numhandles, entrylen;
  1758.     unsigned int access, devinfo, progpsp;
  1759.     long length, offset;
  1760.     int heading = 0;
  1761.   
  1762.     regs.h.ah = 0x52;       /* DOS list of lists */
  1763.     intdosx(®s, ®s, &segregs);
  1764.   
  1765.     /* make a pointer to start of master list */
  1766.     plist = (char far *) MK_FP(segregs.es, regs.x.bx);
  1767.   
  1768.     /* pointer to start of file table */
  1769.     pfiletab = (char far *) MK_FP(*(int far *) (plist + 6), *(int far *) (plist + 4));
  1770.   
  1771.     switch (_osmajor) {
  1772.         case 2:
  1773.             entrylen = 40;  /* DOS 2.x */
  1774.             break;
  1775.         case 3:
  1776.             entrylen = 53;  /* DOS 3.x */
  1777.             break;
  1778.         case 4:
  1779.         case 5:                 /* DOS 5.x - like dos 4.x */
  1780.         case 6:                 /* and NOW DOS 6.0 also */
  1781.             entrylen = 59;  /* DOS 4.x - I do not know what is in the
  1782.                  * extra 6 bytes */
  1783.             break;
  1784.         default:
  1785.             tprintf("File table not available under %s\n",Taskers[Mtasker]);
  1786.             return 1;
  1787.     }
  1788.   
  1789.     for (;;) {
  1790.         /* pointer to next file table */
  1791.         pnext = (char far *) MK_FP(*(int far *) (pfiletab + 2), *(int far *) (pfiletab + 0));
  1792.         nfiles = *(int far *) (pfiletab + 4);
  1793. #ifdef DEBUG
  1794.         tprintf("\nFile table at %Fp entries for %d files\n", pfiletab, nfiles);
  1795. #endif
  1796.         for (i = 0; i < nfiles; i++) {
  1797.   
  1798.             /*
  1799.              * cycle through all files, quit when we reach an
  1800.              * unused entry
  1801.              */
  1802.             entry = pfiletab + 6 + (i * entrylen);
  1803.             if (_osmajor >= 3) {
  1804.                 name = entry + 32;
  1805.                 strncpy(file, localcopy(name), 11);
  1806.                 file[11] = '\0';
  1807.                 numhandles = *(int far *) (entry + 0);
  1808.                 access = (int) *(char far *) (entry + 2);
  1809.                 length = *(long far *) (entry + 17);
  1810.                 offset = *(long far *) (entry + 21);
  1811.                 devinfo = *(int far *) (entry + 5);
  1812.                 progpsp = *(int far *) (entry + 49);
  1813.             } else {
  1814.                 name = entry + 4;
  1815.                 strncpy(file, localcopy(name), 11);
  1816.                 file[11] = '\0';
  1817.                 numhandles = (int) *(char far *) (entry + 0);
  1818.                 access = (int) *(char far *) (entry + 1);
  1819.                 length = *(long far *) (entry + 19);
  1820.                 offset = *(long far *) (entry + 36);
  1821.                 devinfo = (int) *(char far *) (entry + 27);
  1822.             }
  1823.             if ((strlen(file) > 0) && (numhandles > 0) && !(devinfo & 0x80)) {
  1824.                 if(!heading) {
  1825.                     tputc('\n');
  1826.                     tputs("                 Table of Open Files.\n");
  1827.                     tputs("                 --------------------\n");
  1828.                     tputs("Name           length   offset hnd acc PSP device type/owner\n");
  1829.                     tputs("----           ------   ------ --- --- --- -----------------\n");
  1830.                     heading++;              /* header now printed */
  1831.                 }
  1832.                 tprintf("%8.8s.%3.3s %8ld %8ld  %2d ",
  1833.                 file, &file[8], length, offset, numhandles);
  1834.                 switch (access) {
  1835.                     case 0:
  1836.                         tputs("r  ");
  1837.                         break;
  1838.                     case 1:
  1839.                         tputs("w  ");
  1840.                         break;
  1841.                     case 2:
  1842.                         tputs("rw ");
  1843.                         break;
  1844.                     default:
  1845.                         tputs("   ");
  1846.                 }
  1847.                 if (_osmajor >= 3)
  1848.                     tprintf("%04X ", progpsp);
  1849.                 else
  1850.                     tputs("---- ");
  1851.                 tprintf("drive %c: ", 'A' + (devinfo & 0x1F));
  1852.                 if (devinfo & 0x8000)
  1853.                     tputs("(network) ");
  1854.                 if (_osmajor >= 3) {
  1855.                     /*
  1856.                      * only DOS 3+ can find out
  1857.                      * the name of the program
  1858.                      */
  1859.                     fnsplit(progname(progpsp), NULL, NULL, ownername, ownerext);
  1860.                     tprintf("   [%s%s]\n", strlwr(ownername), strlwr(ownerext));
  1861.                 } else {
  1862.                     tputc('\n');
  1863.                 }
  1864.             }
  1865.             if (strlen(file) == 0)
  1866.                 return 0;
  1867.         }
  1868.         pfiletab = pnext;
  1869.     }
  1870. }
  1871. #endif /* __TURBOC__ */
  1872.   
  1873. /* Make a copy of a string pointed to by a far pointer */
  1874. static char *
  1875. localcopy(s)
  1876. char far *s;
  1877. {
  1878.     static char localstring[256];
  1879.     char far *p = s;
  1880.     char *l = localstring;
  1881.     int i = 0;
  1882.   
  1883.     while (*p != NULL && i++ < 255) {
  1884.         *l++ = *p++;
  1885.     }
  1886.   
  1887.     *l = '\0';
  1888.   
  1889.     return (localstring);
  1890. }
  1891.   
  1892. /*
  1893.  * Return a near pointer to a character string with the full path name of the
  1894.  * program whose PSP is given in the argument.  If the argument is invalid,
  1895.  * this may return gibberish but I don't know how to tell Offset 0x2C in the
  1896.  * PSP in the segment address of the environment of a program.  Beyond the
  1897.  * last environment string is a null marker, a word count (usually 1), then
  1898.  * the full pathname of the owner of the environment This only works for DOS
  1899.  * 3+
  1900.  */
  1901. static char *
  1902. progname(pid)
  1903. unsigned int pid;
  1904. {
  1905.     unsigned far   *envsegptr;      /* Pointer to seg address of
  1906.                      * environment */
  1907.     char far       *envptr; /* Pointer to pid's environment  */
  1908.     unsigned far   *envsizeptr;     /* Pointer to environment size */
  1909.     unsigned        envsize;/* Size of pid's environment */
  1910.     unsigned        ppid;   /* Parent psp address */
  1911.   
  1912.     /* find the parent process psp at offset 0x16 of the psp */
  1913.     ppid = *(unsigned far *) MK_FP(pid, 0x16);
  1914.   
  1915.     /* find the environment at offset 2Ch of the psp */
  1916.     envsegptr = (unsigned far *) MK_FP(pid, 0x2C);
  1917.     envptr = (char far *) MK_FP(*envsegptr, 0);
  1918.   
  1919.     /*
  1920.      * Make a pointer that contains the size of the environment block.
  1921.      * Must point back one paragraph (to the environments MCB plus three
  1922.      * bytes forward (to the MCB block size field).
  1923.      */
  1924.     envsizeptr = (unsigned far *) MK_FP(*envsegptr - 1, 0x3);
  1925.     envsize = *envsizeptr * 16;     /* x 16 turns it into bytes */
  1926.   
  1927.     while (envsize > 0) {
  1928.         /* search for end of environment block, or NULL */
  1929.         while (--envsize && *envptr++);
  1930.   
  1931.         /*
  1932.          * Now check for another NULL immediately following the first
  1933.          * one located and a word count of 0001 following that.
  1934.          */
  1935.         if (!*envptr && *(unsigned far *) (envptr + 1) == 0x1) {
  1936.             envptr += 3;
  1937.             break;
  1938.         }
  1939.     }
  1940.   
  1941.     if (envsize > 0) {
  1942.         /* Owner name found - return it */
  1943.         return (localcopy(envptr));
  1944.     } else {
  1945.         if (pid == ppid) {
  1946.             /*
  1947.              * command.com doesn't leave it's name around, but if
  1948.              * pid = ppid then we know we have a shell
  1949.              */
  1950.             return ("-shell-");
  1951.         } else {
  1952.             return ("unknown");
  1953.         }
  1954.     }
  1955. }
  1956. #endif /*__TURBOC__*/
  1957.   
  1958. int
  1959. doprompt(argc,argv,p)
  1960. int argc;
  1961. char *argv[];
  1962. void *p;
  1963. {
  1964.     return setbool(&DosPrompt,"prompt",argc,argv);
  1965. }
  1966.   
  1967. /* Command history, see also pc.c - WG7J */
  1968. void logcmd(char *cmd) {
  1969.     struct hist *new;
  1970.     char *cp;
  1971.   
  1972.     if(!Maxhistory)     /* don't keep history */
  1973.         return;
  1974.   
  1975.     /* Get rid of \n; this is also done in cmdparse().
  1976.      * We HAVE to do this here, since the string is NOT null-terminated when
  1977.      * it comes from recv_mbuf()  !!!! rip() makes it nullterminated.
  1978.      */
  1979.     rip(cmd);
  1980.     cp = cmd;
  1981.     while(*cp == ' ' || *cp == '\t')
  1982.         cp++;
  1983.     if(!*cp)     /* Empty command */
  1984.         return;
  1985.   
  1986.     if(Histrysize < Maxhistory) {     /* Add new one */
  1987.         Histrysize++;
  1988.         if(!Histry) {           /* Empty list */
  1989.         /* Initialize circular linked list */
  1990.             Histry = mallocw(sizeof(struct hist));
  1991.             Histry->next = Histry->prev = Histry;
  1992.         } else {
  1993.             new = mallocw(sizeof(struct hist));
  1994.         /* Now link it in */
  1995.             Histry->next->prev = new;
  1996.             new->next = Histry->next;
  1997.             new->prev = Histry;
  1998.             Histry->next = new;
  1999.             Histry = new;
  2000.         }
  2001.     } else {
  2002.     /* Maximum number stored already, use the oldest entry */
  2003.         Histry = Histry->next;
  2004.         free(Histry->cmd);
  2005.     }
  2006.     Histry->cmd = strdup(cp);
  2007. }
  2008.   
  2009. int
  2010. dohistory(int argc,char *argv[],void *p) {
  2011.     struct hist *h;
  2012.     int num;
  2013.   
  2014.     if(argc > 1) {
  2015.         Maxhistory = atoi(argv[1]);
  2016.         return 0;
  2017.     }
  2018.     tprintf("Max recall %d\n",Maxhistory);
  2019.     if((h = Histry) == NULL)
  2020.         return 0;
  2021.     num = 0;
  2022.     do {
  2023.         tprintf("%.2d: %s\n",num++,h->cmd);
  2024.         h = h->prev;
  2025.     } while(h != Histry);
  2026.     return 0;
  2027. }
  2028.   
  2029. #ifdef __BORLANDC__
  2030.   
  2031. /* This adds some additional checks to the fopen()
  2032.  * in the Borland C++ Run Time Library.
  2033.  * It fixes problem with users trying to open system devices like
  2034.  * CON, AUX etc and hang a system.
  2035.  * WG7J, 930205
  2036.  * reworked by N5KNX 8/94 to allow output to printers iff PRINTEROK is defined,
  2037.  * AND the printer can accept output.  It's still risky; JNOS can lockup if
  2038.  * the printer won't accept output.
  2039.  */
  2040. #undef fopen
  2041. FILE _FAR *_Cdecl fopen(const char _FAR *__path, const char _FAR *__mode);
  2042.  
  2043. static char *InvalidName[] = {
  2044.     "NUL",
  2045.     "CON","CON:",
  2046.     "AUX","AUX:",
  2047.     "PRN","PRN:",
  2048.     "LPT1","LPT1:",
  2049.     "LPT2","LPT2:",
  2050.     "LPT3","LPT3:",
  2051.     "COM1","COM1:",
  2052.     "COM2","COM2:",
  2053.     "COM3","COM3:",
  2054.     "COM4","COM4:",
  2055.     "MOUSE$",
  2056.     "CLOCK$",
  2057.     NULLCHAR
  2058. };
  2059.   
  2060. FILE *newfopen (const char *filename, const char *type) {
  2061.     char *cp, *cp1;
  2062.     int i,j;
  2063. #include <bios.h>
  2064.   
  2065.     cp = strrchr(filename, '\\');
  2066.     cp1 = strrchr(filename, '/');
  2067.     if (cp < cp1) cp = cp1;
  2068.     if (cp == NULLCHAR) cp = (char *)filename;
  2069.     else cp++;
  2070.     if ((cp1 = strchr(cp, '.')) == NULLCHAR) j = strlen(cp);
  2071.     else j = (int)(cp1 - cp);
  2072.     if (j==0) return NULL;   /* path is to a dir, or entryname is .XXX, clearly bad */
  2073.  
  2074.     for(i=0;InvalidName[i] != NULLCHAR;i++)
  2075.     if(strnicmp(InvalidName[i],cp, j) == 0) {
  2076.         if (strpbrk(type, "wWaA") == NULLCHAR) return NULL;  /* must be writing */
  2077. #if defined(PRINTEROK)
  2078.         j=-1;
  2079.         if (strnicmp(cp, "prn", 3)==0 ) j=0;
  2080.         else if (strnicmp(cp, "lpt", 3)==0) j=(*(cp+3) - '1');
  2081.         if (j>=0 && j<3 && ((i=_bios_printer(2,j,0)&0xb9) == 0x90)) break;  /* must be selected, no errors, not busy */
  2082. #endif
  2083.         return NULL;
  2084.     }
  2085.  
  2086.     return fopen (filename, type);
  2087. }
  2088. #endif /* __BORLANDC__ */
  2089.   
  2090. #ifdef REPEATSESSION
  2091.   
  2092. #if defined(__TURBOC__) && !defined(__BORLANDC__)
  2093. /* N5KNX: TurboC 2.0 lacks _setcursortype(), which we supply here for dorepeat */
  2094. void _setcursortype(int style)
  2095. {
  2096. /* From TurboC++ conio.h: */
  2097. #define _NOCURSOR      0
  2098. #define _SOLIDCURSOR   1
  2099. #define _NORMALCURSOR  2
  2100.   
  2101. /* Int 0x10 reg cx codes: */
  2102. #define   STD_CURSOR      0x0607
  2103. #define   BLK_CURSOR      0x0006
  2104. #define   NO_CURSOR       0x2607
  2105.   
  2106.     union REGS regs;
  2107.   
  2108.     if (style == _NOCURSOR) regs.x.cx = NO_CURSOR;
  2109.     else if (style == _SOLIDCURSOR) regs.x.cx = BLK_CURSOR;
  2110.     else if (style == _NORMALCURSOR) regs.x.cx = STD_CURSOR;
  2111.     else return;
  2112.     regs.x.ax = 0x0100; /* set cursor */
  2113.     int86(0x10, ®s, ®s);
  2114. }
  2115. #endif
  2116.   
  2117. /* Repeat a command - taken from 930104 KA9Q NOS
  2118.    WA3DSP 1/93
  2119. */
  2120. int
  2121. dorepeat(argc,argv,p)
  2122. int argc;
  2123. char *argv[];
  2124. void *p;
  2125. {
  2126.     int32 interval;
  2127.     int ret;
  2128.     struct session *sp;
  2129.   
  2130.     if(isdigit(argv[1][0])){
  2131.         interval = atol(argv[1]);
  2132.         argc--;
  2133.         argv++;
  2134.     } else {
  2135.         interval = MSPTICK;
  2136.     }
  2137.     if((sp = newsession(argv[2],REPEAT,1)) == NULLSESSION){
  2138.         tputs("Too many sessions\n");
  2139.         return 1;
  2140.     }
  2141.     _setcursortype(_NOCURSOR);
  2142.     while(sp==Current){
  2143.         /*  clrscr(); */
  2144.         /* gotoxy seems to work better - turn cursor off?? */
  2145.         gotoxy(1,1);
  2146.         ret = subcmd(Cmds,argc,argv,p);
  2147.         if(ret != 0 || pause(interval) == -1)
  2148.             break;
  2149.     }
  2150.     _setcursortype(_NORMALCURSOR);
  2151.     freesession(sp);
  2152.     return 0;
  2153. }
  2154. #endif /* REPEATSESSION */
  2155.   
  2156.   
  2157. /* Index given mailbox files */
  2158. int doindex(int argc,char *argv[],void *p) {
  2159.     int i;
  2160.   
  2161.     for(i=1;i<argc;i++) {
  2162.         if(*argv[i] == '*') {
  2163.             UpdateIndex(NULL,1);
  2164.             /* No reason to do others */
  2165.             return 0;
  2166.         } else {
  2167.             dirformat(argv[i]);
  2168.             /* Attempt to lock the mail file! */
  2169.             if(mlock(Mailspool,argv[i])) {
  2170.                 tprintf("Can not lock '%s/%s.txt'!\n",Mailspool,argv[i]);
  2171.                 continue;
  2172.             }
  2173.             if(IndexFile(argv[i],0) != 0)
  2174.                 tprintf("Error writing index file for %s\n",argv[i]);
  2175.             /* Remove the lock */
  2176.             rmlock(Mailspool,argv[i]);
  2177.         }
  2178.     }
  2179.   
  2180.     return 0;
  2181. }
  2182.   
  2183. /* interpret a string "f+b", where f and b are numbers indicating
  2184.  * foreground and background colors to make up the text attribute
  2185.  */
  2186. void GiveColor(char *s,char *attr) {
  2187.     char *cp;
  2188.   
  2189.     if((cp=strchr(s,'+')) != NULL) {
  2190.         *cp++ = '\0';
  2191.         *attr = (char) atoi(s) & 0x0f;  /* Foreground color */
  2192.         *attr += ((char) atoi(cp) & 0x07) << 4;  /* Background, no blinking ! */
  2193.     }
  2194. }
  2195.